----------The Queen of Phobos----------
A 4am crack                  2018-03-18
---------------------------------------

Name: The Queen of Phobos
Genre: adventure
Year: 1982
Credits: story & artwork by William R.
  Crawford; programming by Paul L.
  Berker; thanks to Dav Holle & Adrian
  Ferret
Publisher: Phoenix Software
Platform: Apple ][+ or later
Media: 5.25-inch disk
Sides: 1
OS: custom
Previous cracks: none (Asimov has an
  uncracked .nib image)

                   ~

               Chapter 0
 In Which Various Automated Tools Fail
          In Interesting Ways


COPYA
- immediate disk read error
- gets a participation trophy just for
  showing up

Locksmith Fast Disk Backup
- unable to read any track

EDD 4 bit copy (no sync, no count)
- works

Copy ][+ nibble editor
- T00-T1A have modified epilogues
  ($ED ** instead of $DE $AA)
- some tracks (2, 3, 6, 7, &c.) also
  have modified address prologue
  ($D4 $AA $96 instead of $D5 $AA $96)
- T1B+ unformatted (hi-res disk scan
  confirms this)

Disk Fixer
- T00 -> custom bootloader
- ignoring epilogues, I can read 0, 1,
  4, 5, ...
- using address prologue $D4 $AA $96, I
  can read the other tracks as well
  (2, 3, 6, 7, ...)
- no sign of DOS, disk catalog, or any
  normalcy
- disk volume is $00, which is probably
  going to be significant given who was
  mentioned on the credits page (Dav
  Holle, who wrote the protection for
  Thunderbombs and Crime Wave -- see
  cracks #1697 and #1676 for details)

Why didn't COPYA work?
  hahahahahahahahaha

Why didn't Locksmith FDB work?
  ditto

EDD worked. What does that tell us?
  Probably no nibble check, quarter
  tracks, half tracks, spiral tracks,
  timing bits. Just a custom bootloader
  and a flexible RWTS that accepts both
  $D4 and $D5.

Next steps:

  1. Passport to convert the disk to a
     standard format (normalizing the
     prologues and epilogues)
  2. Patch the RWTS to read standard
     prologues and epilogues (might not
     even be necessary, depending on
     how it's written)
  3. Declare victory (*)

(*) go to the gym

                   ~

               Chapter 1
 In Which Our Automated Tools Take Us
     Just About As Far As They Can


The 2017-12-27 development version of
Passport successfully auto-converted
the disk to a standard format. The
built-in RWTS was designed to read this
kind of alternating D4/D5 prologue (it
was very common), and the adaptive RWTS
correctly determined the first epilogue
nibble (DA) and enforced it on the rest
of the sectors. All in all, I have high
confidence in the integrity of this
conversion.

Here is the Passport transcript:

                 --v--

READING FROM S6,D1
USING BUILT-IN RWTS
T22 IS UNFORMATTED
WRITING TO RAM DISK
T21 IS UNFORMATTED
T20 IS UNFORMATTED
T1F IS UNFORMATTED
T1E IS UNFORMATTED
T1D IS UNFORMATTED
T1C IS UNFORMATTED
T1B IS UNFORMATTED
WRITING TO S5,D2

THE DISK WAS COPIED SUCCESSFULLY, BUT
PASSPORT DID NOT APPLY ANY PATCHES.

                 --^--

The copy that Passport produces can not
read itself, which is not entirely
unexpected. It is most likely enforcing
the custom $ED epilogue, which is now
the standard $DE $AA $EB. A quick
sector search for "BD 8C C0" (the 6502
opcode for "LDA $C08C,X", which reads
the data latch from a drive indexed by
the X register) finds two clusters of
RWTS code. That's one more RWTS than I
was hoping for, but okay.

                 --v--

------------- DISK SEARCH -------------

$00/$0D-$26   $00/$0D-$30   $00/$0D-$3B
$00/$0D-$76   $00/$0D-$8C   $00/$0D-$97
$00/$0D-$A2   $00/$0D-$AF   $00/$0D-$B7
$00/$0D-$C9   $04/$04-$01   $04/$04-$0B
$04/$04-$15   $04/$04-$90   $04/$04-$A4
$04/$05-$1C   $04/$05-$32   $04/$05-$54
$04/$05-$66   $04/$05-$71   $04/$05-$7C
$04/$05-$89   $04/$05-$91   $04/$05-$A4
$04/$06-$C7

                 --^--

The code on T00,S0D is straightforward.
As I expected, it matches a single $ED
for the epilogue of both the address
and data fields.

                 --v--

T00,S0D
----------- DISASSEMBLY MODE ----------
; match data field epilogue
006C:BC 8C C0       LDY   $C08C,X
006F:10 FB          BPL   $006C
0071:D9 D6 02       LDA   $02D6,Y
0074:D0 09          BNE   $007F
0076:BD 8C C0       LDA   $C08C,X
0079:10 FB          BPL   $0076
007B:C9 ED          CMP   #$ED    <-- !
007D:F0 53          BEQ   $00D2
007F:38             SEC
0080:60             RTS

...

; parse address field into $F7..$FA in
; zero page
00B7:BD 8C C0       LDA   $C08C,X
00BA:10 FB          BPL   $00B7
00BC:25 F4          AND   $F4
00BE:99 F7 00       STA   $00F7,Y
00C1:45 F5          EOR   $F5
00C3:88             DEY
00C4:10 E7          BPL   $00AD
00C6:A8             TAY
00C7:D0 B6          BNE   $007F

; match address field epilogue
00C9:BD 8C C0       LDA   $C08C,X
00CC:10 FB          BPL   $00C9
00CE:C9 ED          CMP   #$ED    <-- !
00D0:D0 AD          BNE   $007F
00D2:18             CLC
00D3:60             RTS

                 --^--

While we're admiring custom RWTS code,
I want to point out this beauty, which
I've never seen done quite this way
before:

                 --v--

; match $D4 or $D5 for the first nibble
; of the address prologue
008C:BD 8C C0       LDA   $C08C,X
008F:10 FB          BPL   $008C
0091:09 01          ORA   #$01    <-- !
0093:C9 D5          CMP   #$D5
0095:D0 EE          BNE   $0085

                 --^--

The more common technique takes the
nibble from the data latch and LSRs it,
then compares it to #$6A. That will
match both $D4 and $D5. But "ORA #$01"
plus "CMP #$D5" accomplishes the same
thing in the same number of CPU cycles.

                   ~

               Chapter 2
   In Which It Pays To Pay Attention


Patching the two epilogue nibbles

T00,S0D,$7C: ED -> DE
T00,S0D,$CF: ED -> DE

is necessary but not sufficient. My
copy still refuses to boot, making no
more progress than before I reset the
epilogues. It's not clear why.

But I have a secret weapon: knowledge
of other Dav Holle protections. Do you
remember that the disk volume was 000
on the original disk? Dav enjoys using
that for unrelated purposes.

The address field parser stored each
sector's address field values into zero
page $F7..$FA. That means the disk
volume will end up in $FA.

A quick search for "A5 FA" finds that,
indeed, the RWTS is using this value
and assuming it is zero. (It isn't; on
my copy, the disk volume number is the
default, 254.)

                 --v--

T00,S0D
----------- DISASSEMBLY MODE -----------
; last nibble of data prologue
0039:A0 56          LDY   #$56
003B:BD 8C C0       LDA   $C08C,X
003E:10 FB          BPL   $003B
0040:C9 AD          CMP   #$AD
0042:D0 E7          BNE   $002B

; beginning of data field decoding
0044:A5 FA          LDA   $FA     <-- !
0046:E6 00          INC   $00
0048:88             DEY
0049:84 F4          STY   $F4
004B:BC 8C C0       LDY   $C08C,X
004E:10 FB          BPL   $004B
0050:59 D6 02       EOR   $02D6,Y

                 --^--

Aha! We are using the disk volume in
$FA to initialize the checksum for the
data field. Since my disk volume is no
longer 000, this custom RWTS is using
the wrong initial checksum (254) and
thinks that every sector is damaged.

The solution is to initialize the
accumulator with #$00 as a constant,
instead of relying on the (unrelated)
disk volume number.

T00,S0D,$44: A5FA -> A900

Now my copy boots much further -- all
the way to displaying the graphical
title page!

Then it starts grinding.

It's almost like there are two RWTS---
oh, right. There are.

                   ~

               Chapter 3
   In Which It Looks Like Everything
 Is Going To Go Right For Five Minutes


My initial scan for "BD 8C C0" found
two clusters of RWTS-looking code. The
first, on track 0, appears to be
sufficiently patched now. But it also
appears that it's only used for the
initial load, as far as the title page,
before control transfers to the second
RWTS on track 4.

Sure enough, the second RWTS on track 4
is just as strict about enforcing the
non-standard epilogues:

                 --v--

T04,S04
----------- DISASSEMBLY MODE ----------
; match data field epilogue
0090:BD 8C C0       LDA   $C08C,X
0093:10 FB          BPL   $0090
0095:C9 ED          CMP   #$ED    <-- !
0097:D0 02          BNE   $009B
0099:18             CLC
009A:24 38          BIT   $38
009C:68             PLA
009D:A0 55          LDY   #$55
009F:91 10          STA   ($10),Y
00A1:60             RTS

...

[continued on T04,S05]
; parse address field into $18..$1B
; in zero page
0091:BD 8C C0       LDA   $C08C,X
0094:10 FB          BPL   $0091
0096:25 03          AND   $03
0098:99 18 00       STA   $0018,Y
009B:45 02          EOR   $02
009D:88             DEY
009E:10 E7          BPL   $0087
00A0:A8             TAY
00A1:D0 1E          BNE   $00C1
00A3:EA             NOP

; match address field epilogue
00A4:BD 8C C0       LDA   $C08C,X
00A7:10 FB          BPL   $00A4
00A9:C9 ED          CMP   #$ED    <-- !
00AB:D0 14          BNE   $00C1
00AD:18             CLC
00AE:60             RTS

                 --^--

But wait! This second RWTS also does
the same trick of relying on the disk
volume number (now in zero page $1B):

                 --v--

T04,S04
----------- DISASSEMBLY MODE ----------
0001:BD 8C C0       LDA   $C08C,X
0004:10 FB          BPL   $0001
0006:49 D5          EOR   #$D5
0008:D0 F4          BNE   $FFFE
000A:EA             NOP
000B:BD 8C C0       LDA   $C08C,X
000E:10 FB          BPL   $000B
0010:C9 AA          CMP   #$AA
0012:D0 F2          BNE   $0006
0014:EA             NOP
0015:BD 8C C0       LDA   $C08C,X
0018:10 FB          BPL   $0015
001A:C9 AD          CMP   #$AD
001C:D0 E8          BNE   $0006
001E:A0 AA          LDY   #$AA
0020:A5 1B          LDA   $1B     <-- !
0022:E6 4E          INC   $4E
0024:85 03          STA   $03
0026:AE 8C C0       LDX   $C08C
0029:10 FB          BPL   $0026
002B:BD 00 B7       LDA   $B700,X
002E:99 56 02       STA   $0256,Y
0031:45 03          EOR   $03

                 --^--

Furthermore, this is a full read/write
RWTS, so there are additional instances
of $ED in the disk writing code that
will also need to be reset to $DE.

All told:

T04,S05,$A9: ED -> DE     ; addr read
T04,S04,$96: ED -> DE     ; data read
T04,S06,$B5: ED -> DE     ; addr write
T04,S05,$45: ED -> DE     ; data write
T04,S04,$20: A51B -> A900 ; disk volume

]PR#6
...boots into game, everything works...

Except...

                   ~

               Chapter 4
 In Which Everything Goes Wrong Again,
             Very Rapidly


The first thing I did in-game is push
the button on my ship's console. It is
supposed to do this:

                 --v--

**>COMMAND? PUSH BUTTON

A VOICE CRACKLES OVER THE RADIO:'WHAT
ARE YOU DOING SITTING IN YOUR SHIP?!
GET THAT MASK!'

                 --^--

On the original disk, it stops there.
But on my copy, it continues...

                 --v--

SUDDENLY, THE WALLS AROUND YOU DISSOLVE
IN A SHEET OF NUCLEAR FIRE, AND YOU FEEL
THE FLESH MELTING FROM YOUR BONES.

YOU HAVE JUST GIVEN YOUR LIFE FOR YOUR
PLANET. PRESS [RETURN] TO RESTART.

                 --^--

If the game detects you're using a
pirated copy, it literally melts your
flesh off. That's great. DRM is great.

On a hunch, I went back to my trusty
sector editor and searched for "A5 1B"
(the instruction to get the disk volume
number, as stored in zero page by the
RWTS on track 4). And I got a hit, not
on track 4, but far away on track 8.

                 --v--

T08,S01
----------- DISASSEMBLY MODE ----------
00FA:A5 1B          LDA   $1B
00FC:F0 0C          BEQ   $010A
00FE:A9 01          LDA   #$01

                 --^--

I don't even know where the rest of
this code is. (It doesn't appear to
continue on either T08,S00 or T08,S02.)
But it is most definitely checking if
zero page $1B is 0 and going down two
different code paths.

So, maybe...

T08,S01,$FA: A51B -> A900

]PR#6
...no longer melts your flesh off...

Quod erat liberandum.

                   ~

            Acknowledgments


Thanks to Ian Baronofsky for lending me
original disk.

---------------------------------------
A 4am crack                    No. 1723
------------------EOF------------------
